Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Writing a Simple Publisher and Subscriber
Description: This tutorial covers how to write a publisher and subscriber node in ruby.Tutorial Level: BEGINNER
Contents
Writing the Publisher Node
"Node" is the ROS term for an executable that is connected to the ROS network. Here we'll create the publisher ("talker") node which will continually broadcast a message. At first let's create rb_tutorials package which depends on rosruby and std_msgs with this command
roscreate-pkg rb_tutorials rosruby std_msgs
The Code
Create the nodes/talker.rb file within the rb_tutorials package and paste the following inside it:
1 #!/usr/bin/env ruby
2 require 'ros'
3 ROS::load_manifest('rb_tutorials')
4 require 'std_msgs/String'
5
6 node = ROS::Node.new('talker')
7 publisher = node.advertise('/chatter', Std_msgs::String)
8 sleep(1)
9 msg = Std_msgs::String.new
10
11 i = 0
12 while node.ok?
13 msg.data = "Hello, rosruby!: #{i}"
14 publisher.publish(msg)
15 node.loginfo(msg.data)
16 sleep(1.0)
17 i += 1
18 end
Don't forget to make the node executable:
chmod +x nodes/talker.rb
The Code Explained
Now, let's break the code down.
Every ROS Node will have this declaration at the top. The first line makes sure your script is executable and the second requires rosruby libraries. The third reads in your manifest.xml file and add all the dependencies listed there to your RUBYLIB. This will be important for the next line of code.
4 require 'std_msgs/String'
The ROS::load_manifest() enabled it to find std_msgs, which were declared as dependencies in the manifest.xml you just wrote. The std_msgs.msg require is so that we can reuse the std_msgs/String message type (a simple string container) for publishing.
<
6 node = ROS::Node.new('talker')
This line create a ROS Node for ROS communication. In this case, your node will take on the name talker. Different from roscpp or rospy, rosruby uses a Node object directly instead of NodeHandle. You have to keep this node object to create any ROS communication object.
7 publisher = node.advertise('/chatter', Std_msgs::String)
This section of code defines the talker's interface to the rest of ROS. publisher = node.advertise('/chatter', Std_msgs::String) declares that your node is publishing to the chatter topic using the message type Std_msgs::String. Ruby's class/module name must be started with capital letter, the name is Std_msgs::String, not std_msgs::String.
This loop is a fairly standard rosruby construct: checking the node.ok? flag and then doing work. You have to check ok? to check if your program should exit (e.g. if there is a Ctrl-C or otherwise). In this case, the "work" is a call to publisher.publish() that publishes to our chatter.
This loop also calls node.loginfo(str), which performs triple-duty: the messages gets printed to screen, it gets written to the Node's log file, and it gets written to rosout. rosout is a handy for debugging: you can pull up messages using rxconsole instead of having to find the console window with your Node's output.
Std_msgs::String is a very simple message type, so you may be wondering what it looks like to publish more complicated types. You can pass in no arguments and initialize the fields directly, e.g.
msg = Std_msgs::String.new msg.data = str
or you can initialize some of the fields and leave the rest with default values:
msg = Std_msgs::String.new(:data=>str)
Writing the Subscriber Node
The Code
Create the nodes/listener.rb file within the rb_tutorials package and paste the following inside it:
Don't forget to make the node executable:
chmod +x nodes/listener.rb
The Code Explained
The code for listener.rb is similar to talker.rb, except we've introduced a new callback-based mechanism for subscribing to messages.
This declares that your node subscribes to the chatter topic which is of type Std_msgs::String. When new messages are received, callback is invoked with the message as the first argument.
The final addition, node.spin wait message and affects subscriber callback functions.